// Package main 是kris程序的主模块。
package main

import (
	"flag"
	"fmt"
	. "org.xx/kris2/common"
	_java "org.xx/kris2/java"
	_xml "org.xx/kris2/xml"
	"path/filepath"
	"strings"
)

var (
	// 是否显示帮助信息。
	h bool
	// 是否显示运行过程。
	v bool
	// 源文件。
	source string
	// 生成代码的目标目录。
	destination string
	// 最上层的包名或者名字空间。
	package_ string
	// 生成代码的目标语言。
	target string
	// 生成代码的目标数据库。
	db string
)

func init() {
	flag.BoolVar(&h, "help", false, "Show this help")
	flag.StringVar(&source, "source", "statements.xml", "Source file(*.xml)")
	flag.StringVar(&destination, "destination", ".", "Destination base path")
	flag.StringVar(&package_, "package", "", "Package or namespace of target code")
	flag.StringVar(&target, "target", LANG_JAVA, "Language of target code")
	flag.StringVar(&db, "database", DB_H2, "Database of target code")
	flag.BoolVar(&v, "x", false, "Show verbose")
}

func main() {
	var err error
	flag.Parse()

	// Check command line flags

	if h {
		printVersion()
		flag.Usage()
		return
	}

	// 检查目标目录，必须是一个有效的目录名，可以是相对路径或者绝对路径。
	// 如果不存在，应当在生成代码时创建。
	if len(destination) == 0 {
		PrintError("Argument %q must not be empty", "destination")
		return
	}
	destination, err = filepath.Abs(destination)
	if err != nil {
		PrintError("Argument %q must be a valid relative or absolute path", "destination")
		return
	}

	// 检查顶级包名，不能为空。
	if len(package_) == 0 {
		PrintError("Argument %q must not be empty", "package")
		return
	}
	package_ = strings.ToLower(package_)

	ALL_LANG_VALUES := []string{LANG_JAVA, LANG_CSHARP, LANG_PYTHON, LANG_GO}
	ALL_DB_VALUES := []string{DB_H2, DB_ORACLE, DB_MYSQL, DB_POSTGRES, DB_SQLSERVER}

	// 检查目标语言类型。
	target = strings.ToLower(target)
	if !ContainsString(ALL_LANG_VALUES, target) {
		PrintError("Argument %q must in %v", target, ALL_LANG_VALUES)
	}

	// 检查目标数据库类型，不能超出可选范围。
	if !ContainsString(ALL_DB_VALUES, db) {
		PrintError("Argument %q must in %v", db, ALL_DB_VALUES)
	}

	if v {
		EnableVerbose()
	}

	printVersion()

	PrintVerbose("Loading entities and modules from %q ...", source)

	dbEntities, dbModules := _xml.ParseDbXml(source)

	PrintInfo("%d entity(ies) and %d module(s) loaded", len(dbEntities), len(dbModules))

	switch target {
	case LANG_JAVA:
		PrintVerbose("Generating entities ...")
		_java.WriteEntitiesCode(package_, destination, dbEntities)
		PrintVerbose("Generating entity mappers ...")
		_java.WriteEntityMappersCode(package_, destination, dbEntities)
		PrintVerbose("Generating modules ...")
		_java.WriteModulesCode(package_, destination, db, dbEntities, dbModules)
	case LANG_CSHARP:
		panic("C# not supported")
	case LANG_PYTHON:
		panic("Python not supported")
	case LANG_GO:
		panic("Golang not supported")
	default:
		panic(fmt.Sprintf("%s not supported", target))
	}
}

// 打印输出版本信息。
func printVersion() {
	fmt.Printf("kris %s\n", APP_VERSION)
	fmt.Println("Automatic data-access-layer code generator")
	fmt.Println()
}
